/*
STL set/multiset 容器
所有元素在插入时自动被排序，属于关联式容器，底层是二叉树实现, set与multiset用法一致
set与multiset的区别
  set不允许容器中有重复元素
  multiset允许容器中有重复元素

set 构造和赋值
  函数原型
    set<T> st;  // 默认构造函数
    set(initializer_list<T> li);  // 列表初始化il构造容器
    set(const set& st);  // 拷贝构造函数
    set& operator=(const set& st);  // 重载等号操作符

set 大小和交换
  函数原型
    empty();  // 判断容器是否为空
    size();  // 返回容器内元素数量
    swap(st);  // 交换两个集合

set 插入和删除
  函数原型
    insert(elem);  // 向容器中插入元素, 返回插入结果
    erase(pos);  // 删除pos位置的元素， 返回下一个元素的迭代器
    erase(elem);  // 删除容器中值为elem的元素
    erase(beg, end);  // 删除[beg, end)区间内的元素
    clear();  // 删除容器内所有的元素

set 查找和统计
  函数原型
    find(key);  // 查找key是否存在，存在返回改key的元素的迭代器，不存在返回set.end();
    count(key);  // 统计key元素的个数

pair队组创建
  成对出现的数据，利用队组可以返回两个数据
  函数原型
    pair<type, type> p(value1, value2);
    pair<type, type> p = make_pair(value1, value2);

set 排序
  利用仿函数可以改变默认(从小到大)排序规则 
  注意 要写成常函数 不然编译会报错
*/

#include <iostream>
#include <set>
#include <string>
using namespace std;

template <typename T>
void print_st(const set<T> &s)
{
    for (auto it = s.begin(); it != s.end(); it++)
        cout << *it << " ";
    cout << endl;
}

// set 构造和赋值
void func1()
{
    cout << "---------------------- set constribute&assign ---------------------" << endl;
    set<int> s1 = {1, 2, 3, 1, 4, 2}; // set(initializer_list<T> il)
    print_st<int>(s1);                // 1 2 3 4

    set<char> s2; // set<T> st
    s2.insert('b');
    s2.insert('a');
    s2.insert('c');
    print_st<char>(s2); // a b c

    set<char> s3(s2);
    print_st<char>(s2);

    set<char> s4;
    s4 = s3;
    print_st<char>(s4);
}

// set 大小和交换
void func2()
{
    cout << "---------------------- set size&swap ---------------------" << endl;
    set<string> s1 = {"hello", "c++", "stl", "set"};
    cout << "s1: -->  ";
    print_st<string>(s1);
    cout << "s1.empty: " << s1.empty() << " s1.size: " << s1.size() << endl;

    set<string> s2 = {"hello", "world"};
    cout << "s2: -->  ";
    print_st<string>(s2);

    cout << "- swap s1, s2 -" << endl;
    s1.swap(s2);
    cout << "s1: -->  ";
    print_st<string>(s1);
    cout << "s2: -->  ";
    print_st<string>(s2);
}

// set 插入与删除
void func3()
{
    cout << "---------------------- set insert&erase ---------------------" << endl;
    set<int> s1;
    s1.insert(9);
    s1.insert(4);
    s1.insert(3);
    s1.insert(6);
    print_st<int>(s1);

    s1.erase(3); // erase(elem)
    print_st<int>(s1);

    set<int>::iterator it = s1.begin();
    it++;
    s1.erase(it); // erase(pos)
    print_st<int>(s1);

    s1.clear();
    print_st<int>(s1);
}

// set 查找和统计
void func4()
{
    cout << "---------------------- set find&count ---------------------" << endl;
    set<string> s1 = {"hi", "c++", "stl", "set", "set"};
    print_st<string>(s1);

    // set<string>::iterator it=s1.find("s"); // 要查找完整的元素，不能是元素的一部分 这样返回的是 s1.end() 下面的打印会指针越界
    // cout << "s1.find(s): " << *it << endl; // Segmentation fault (core dumped)

    set<string>::iterator it = s1.find("stl");
    cout << "s1.find(stl): " << *it << endl; // stl

    int c = s1.count("set");
    cout << "s1.count(set): " << c << endl; // 1

    // multiset
    multiset<string> ms1 = {"hi", "c++", "stl", "set", "set"};

    multiset<string>::iterator mit = ms1.find("set");
    cout << "s1.find(set): " << *mit << endl; // set

    int mc = ms1.count("set");
    cout << "ms1.count(set): " << mc << endl; // 2
}

// pair对组创建
void func5()
{
    cout << "---------------------- pair ---------------------" << endl;
    pair<string, int> p1("aliex", 20);
    cout << "name: " << p1.first << " age: " << p1.second << endl;

    pair<string, int> p2 = make_pair("jordan", 50);
    cout << "name: " << p2.first << " age: " << p2.second << endl;
}

// set 排序
// 这种方式不行，在list中可以用 在这里不行, 要用仿函数
// bool mycompare(int v1, int v2)
// {
//     return v1 > v2;
// }

class MyConpare
{
public:
    bool operator()(int v1, int v2) const  // 一定要写成常函数
    {
        return v1 > v2;
    }
};

void func6()
{
    cout << "---------------------- sort ---------------------" << endl;
    cout << "- default sort -> " << endl;
    set<int> s1 = {1, 3, 2, 7, 5, 6, 4, 5};
    print_st<int>(s1);

    cout << "- customize sort -> " << endl;
    set<int, MyConpare> s2 = {1, 3, 2, 7, 5, 6, 4, 5};
    // print_st<int>(s2);  // 这里用打印函数会有类型错误问题 我看别人用类型自动推导可以打印，但我的不行
    for (set<int, MyConpare>::iterator it = s2.begin(); it != s2.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

int main()
{
    func1(); // set 构造与赋值
    func2(); // set 大小与交换
    func3(); // set 插入与删除
    func4(); // set 查找与统计
    func5(); // pair对组创建
    func6(); // set 排序

    return 0;
}